package com.hispot.download;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.SocketException;
import java.net.UnknownHostException;

import okhttp3.Request;
import okhttp3.Response;

/**
 * Created by ASUS-PC on 2016/11/13.
 */

class FileDownloadImp implements Runnable {

    private static final String TAG = "FileDownloadImp";

    public FileDownloadImp(FileDownloadSQLiteHelper sqLiteHelper, String url, String fileName, FileDownloadListener downloadListener, FileDownloadManager downloadManager) {
        this.sqLiteHelper = sqLiteHelper;
        this.url = url;
        this.fileName = fileName;
        this.downloadListener = downloadListener;
        this.downloadManager = downloadManager;
        onWaiting();
    }

    @Override
    public void run() {

        String filePath = FileDownloadManager.DOWNLOAD_DIR + fileName;

        isDownloading = true;

        Message message1 = handler.obtainMessage();
        message1.what = FileDownloadStatus.Start;
        handler.sendMessage(message1);

        long startPoint = FileDownloadUtils.getStartPoint(sqLiteHelper, url);

        startPoint = FileDownloadUtils.checkPoint(startPoint,filePath);

        Request request = new Request.Builder().url(url).header("Range", "bytes=" + startPoint + "-").build();
        RandomAccessFile accessFile = null;
        InputStream inputStream = null;
        int code = 0;
        try {
            int sum;

            try {
                Response response = FileDownloadManager.getHttpClient().newCall(request).execute();

                code = response.code();

                if (code != 206) {
                    Message message = handler.obtainMessage();
                    message.what = FileDownloadError.UN_KNOW;
                    Bundle bundle = new Bundle();
                    bundle.putInt("code", code);
                    message.setData(bundle);
                    handler.sendMessage(message);
                    return;
                }

                inputStream = response.body().byteStream();
                byte[] bytes = new byte[10 * 1024];

                boolean b = FileDownloadUtils.checkDirExistsAndCreate(FileDownloadManager.DOWNLOAD_DIR);

                long fileLength = response.body().contentLength();

                accessFile = new RandomAccessFile(filePath, "rw");
                accessFile.seek(startPoint);
                long point = startPoint;
                while ((sum = inputStream.read(bytes)) != -1 && isDownloading) {
                    accessFile.write(bytes, 0, sum);
                    startPoint += sum;
//                    FileDownloadUtils.upDateDatabase(sqLiteHelper, url, startPoint, fileLength + point, FileDownloadStatus.Downloading, 4);
                    sendInfoMessage(FileDownloadStatus.Downloading, startPoint, fileLength + point);
                }
                int status;
                if (sum == -1) {
                    status = FileDownloadStatus.Complete;
                } else {
                    status = FileDownloadStatus.Pause;
                }
                FileDownloadUtils.upDateDatabase(sqLiteHelper, url, startPoint, fileLength + point, status);

                sendInfoMessage(status, startPoint, fileLength + point);
            } finally {
                if (inputStream != null) inputStream.close();
                if (accessFile != null) accessFile.close();

                if (downloadManager != null) {
                    downloadManager.getFileDownloadImpMap().remove(url);
                }
            }

        } catch (IOException e) {
            Log.e(TAG, "run: " + e.fillInStackTrace());
            e.printStackTrace();
            isDownloading = false;
            Message message = handler.obtainMessage();
            Bundle bundle = new Bundle();
            if (e instanceof FileNotFoundException) {
                message.what = FileDownloadError.FILE_NOT_FOUND;
            } else if (e instanceof SocketException) {
                message.what = FileDownloadError.TIME_OUT;
            } else if (e instanceof UnknownHostException) {
                message.what = FileDownloadError.UN_KNOW_HOST;
            } else {
                message.what = FileDownloadError.UN_KNOW;
            }
            bundle.putInt("code", code);
            bundle.putString("error", e.fillInStackTrace().toString());
            handler.sendMessage(message);
        }
    }

    private void onWaiting() {

        FileDownloadModel model = FileDownloadUtils.getFileDownloadStatus(sqLiteHelper, url);
        if (downloadListener != null) {
            downloadListener.onWaiting(url, model.soFar, model.total, model.percent);
        }
        FileDownloadUtils.upDateDatabase(sqLiteHelper, url, model.soFar, model.total, FileDownloadStatus.Waiting);
    }

    private void sendInfoMessage(int status, long soFar, long total) {
        Message message = handler.obtainMessage();
        message.what = status;
        Bundle bundle = new Bundle();
        bundle.putLong("soFar", soFar);
        bundle.putLong("total", total);
        message.setData(bundle);
        handler.sendMessage(message);
    }

    private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {

            if (downloadListener != null) {

                long soFar = msg.getData().getLong("soFar");
                long total = msg.getData().getLong("total");
                int percent = (int) ((double) soFar / total * 100);

                switch (msg.what) {
                    case FileDownloadStatus.Downloading:
                        downloadListener.onDownloading(url, soFar, total, percent);
                        mPercent = percent;
                        break;
                    case FileDownloadStatus.Complete:
                        downloadListener.onComplete(url, FileDownloadManager.DOWNLOAD_DIR + fileName);
                        break;
                    case FileDownloadStatus.Pause:
                        downloadListener.onPause(url, soFar, total, percent);
                        break;
                    case FileDownloadStatus.Start:
                        downloadListener.onStart(url);
                        break;
                    case FileDownloadError.TIME_OUT:

                    case FileDownloadError.FILE_NOT_FOUND:

                    case FileDownloadError.UN_KNOW_HOST:

                    case FileDownloadError.UN_KNOW:
                        FileDownloadUtils.upDateDatabase(sqLiteHelper, url, 0, 1, msg.what);
                        Log.e(TAG, "handleMessage: error="+msg.what);
                        downloadListener.onError(url, msg.getData().getInt("code"), msg.what, msg.getData().getString("error"));
                        downloadManager.start(url,fileName);
                        break;
                }
            }

        }
    };

    public void pause() {
        if (!isDownloading){
            FileDownloadModel fileDownloadStatus = downloadManager.getFileDownloadStatus(url);
            if (fileDownloadStatus.status == FileDownloadStatus.Waiting){
                FileDownloadUtils.upDateDatabase(sqLiteHelper, url, 0, 1, FileDownloadStatus.Pause);
            }
        }
        isDownloading = false;
    }

    public boolean isDownloading() {
        return isDownloading;
    }

    public int getPercent() {
        return mPercent;
    }

    private FileDownloadSQLiteHelper sqLiteHelper;

    private String url;

    private boolean isDownloading;

    private String fileName;

    private FileDownloadListener downloadListener;

    private FileDownloadManager downloadManager;

    private int mPercent;
}

